#!/usr/bin/python
# -*- coding: utf-8 -*-
"""
Item Module

Mikan Python Web Framework
"""

__author__ = "K.Sonohara"
__status__ = "develop"
__version__ = "0.0.0_36"
__date__    = "2014/01/05"
__license__ = 'LGPL'

# ------------------------------------------------------------
## Import Section
# ------------------------------------------------------------
# Python
import locale
import logging, traceback
from operator import itemgetter, attrgetter
import datetime

# BSON
from bson import ObjectId

# ESiPC
from esipc.resource.iniresource import ESiPCINIFileResourceBundle
from esipc import ESiPCProperty

# Mikan
from mikan.core import MIKAN,AbstractMikan

# ------------------------------------------------------------
## Variable Section
# ------------------------------------------------------------
RESOURCE = ESiPCINIFileResourceBundle(__file__)

# ------------------------------------------------------------
## Function Section
# ------------------------------------------------------------
def _(key, default, locale=None):
	try:
		return RESOURCE.get_string(key, default, locale)
	except:
		return default

# ------------------------------------------------------------
## Class Section
# ------------------------------------------------------------

# ------------------------------------------------------------
## ESiPC Exception Constant
class MIKAN_ITEM(MIKAN):
	CLASS_TYPE_STRING = "string"
	CLASS_TYPE_PASSWORD = "password"
	CLASS_TYPE_SHORT = "short"
	CLASS_TYPE_INT = "int"
	CLASS_TYPE_LONG = "long"
	CLASS_TYPE_TIMESTAMP = "timestamp"
	CLASS_TYPE_TIME = "time"
	CLASS_TYPE_DATE = "date"
	CLASS_TYPE_BOOL = "bool"
	CLASS_TYPE_FLOAT = "float"
	CLASS_TYPE_ITEM = "item"

# ------------------------------------------------------------
## Mikan 抽象アイテム クラス
#
class AbstractMikanItem(AbstractMikan, MIKAN_ITEM):

	# ----------------------------------------------------
	## コンストラクタ
	#  @param self クラス自身
	def __init__(self):
		super(AbstractMikanItem, self).__init__()

	def get_item_name(self):
		return self.itemclassname

	def get_define_name(self):
		return self.itemname.lower()

	def get_base_icon_name(self):
		return self.definename

	def get_icon_name(self):
		try:
			icon = self.iconvalue
			if icon != None:
				if icon != "":
					return icon
		except:
			pass
		return self.baseiconname

	def get_item_class_name(self):
		return self.__class__.__name__

	def get_item_resource(self):
		return RESOURCE

	def get_item_full_class_name(self):
		return u"%s.%s" % (self.__module__, self.__class__.__name__)

	def get_item_resource_key(self, key):
		return "%s_%s" % (self.itemclassname, key)

	def get_item_caption(self):
		key = self.get_item_resource_key("caption")
		if self.islogdebug:
			self.logger.debug(key)

		return self.itemresource.get_string(key, self.itemname, locale.getlocale())

	def get_item_help(self):
		try:
			key = self.get_item_resource_key("help")
			if self.islogdebug:
				self.logger.debug(key)

			return self.itemresource.get_string(key, self.itemcaption, locale.getlocale())
		except:
			pass
		return self.itemcaption

	# ----------------------------------------------------
	## Property
	itemcaption = ESiPCProperty(get_item_caption, None, None)
	itemhelp = ESiPCProperty(get_item_help, None, None)
	itemname = ESiPCProperty(get_item_name, None, None)
	itemclassname = ESiPCProperty(get_item_class_name, None, None)
	itemresource = ESiPCProperty(get_item_resource, None, None)
	itemfullclassname = ESiPCProperty(get_item_full_class_name, None, None)

	baseiconname = ESiPCProperty(get_base_icon_name, None, None)
	iconname = ESiPCProperty(get_icon_name, None, None)
	definename = ESiPCProperty(get_define_name, None, None)


# ------------------------------------------------------------
## Mikan 抽象属性 クラス
#
class AbstractMikanAttribute(AbstractMikanItem):

	# ----------------------------------------------------
	## コンストラクタ
	#  @param self クラス自身
	def __init__(self, readonly=False, unique=False, required=False, dynamic=False, mlist=None, sortkey=0):
		super(AbstractMikanAttribute, self).__init__()

		self.FReadOnly = readonly
		self.FUnique = unique
		self.FRequired = required
		self.FDynamic = dynamic
		self.FList = mlist
		self.FSortKey = sortkey

	def get_item_name(self):
		return super(AbstractMikanAttribute, self).get_item_name().replace("Attribute", "")

	def is_readonly(self):
		return self.FReadOnly

	def is_unique(self):
		return self.FUnique

	def is_required(self):
		return self.FRequired

	def is_dynamic(self):
		return self.FDynamic

	def get_class_type(self):
		return "string"

	def get_list(self):
		return self.FList

	def to_display_value(self, value, db=None):
		try:
			if self.get_list() != None:
				return self.get_list().to_display_value(value, db)
		except:
			# ログ
			self.logger.error(traceback.format_exc())

		if self.classtype == MIKAN_ITEM.CLASS_TYPE_PASSWORD:
			return ""

		return unicode(value)

	def get_sort_key(self):
		return self.FSortKey

	def get_length(self):
		return -1

	def __str__(self):
		return u"%s=%s: %s [%s]" % (self.itemname, self.definename, self.itemcaption, self.classtype)

	# ----------------------------------------------------
	## Property
	sortkey = ESiPCProperty(get_sort_key, None, None)
	length = ESiPCProperty(get_length, None, None)
	classtype = ESiPCProperty(get_class_type, None, None)
	isdynamic = ESiPCProperty(is_dynamic, None, None)
	isrequired = ESiPCProperty(is_required, None, None)
	isunique = ESiPCProperty(is_unique, None, None)
	isreadonly = ESiPCProperty(is_readonly, None, None)
	list = ESiPCProperty(get_list, None, None)


class AbstractURLAttribute(AbstractMikanAttribute):
	# ----------------------------------------------------
	## コンストラクタ
	#  @param self クラス自身
	def __init__(self, readonly=False, unique=False, required=False, dynamic=False, mlist=None, sortkey=0):
		super(AbstractURLAttribute, self).__init__()

class AbstractMailAttribute(AbstractMikanAttribute):
	# ----------------------------------------------------
	## コンストラクタ
	#  @param self クラス自身
	def __init__(self, readonly=False, unique=False, required=False, dynamic=False, mlist=None, sortkey=0):
		super(AbstractMailAttribute, self).__init__()

# ------------------------------------------------------------
## Mikan 抽象定義値 クラス
#
class AbstractMikanConstant(AbstractMikanItem):

	# ----------------------------------------------------
	## コンストラクタ
	#  @param self クラス自身
	def __init__(self):
		super(AbstractMikanConstant, self).__init__()

	def get_item_name(self):
		return super(AbstractMikanConstant, self).get_item_name().replace("Constant", "")

	def get_key(self):
		return None

	def get_object(self):
		o = self.itemcaption
		if (o):
			return o
		return str(self.key)

	def __str__(self):
		return u"%s: %s=%s" % (self.definename, unicode(self.key), self.itemcaption)

	def to_display_value(self):
		return self.itemcaption

	# ----------------------------------------------------
	## Property
	key = ESiPCProperty(get_key, None, None)
	object = ESiPCProperty(get_object, None, None)

# ------------------------------------------------------------
## Mikan 抽象リスト クラス
#
class AbstractMikanList(AbstractMikanItem):

	def get_list(self):
		return None

	def is_entity_list(self):
		try:
			return self.entityclass != None
		except:
			return False

	# ----------------------------------------------------
	## コンストラクタ
	#  @param self クラス自身
	def __init__(self):
		super(AbstractMikanList, self).__init__()

	def get_item_name(self):
		return super(AbstractMikanList, self).get_item_name().replace("List", "")

	def __str__(self):
		return u"%s=%s: [%s]" % (self.itemname, self.itemcaption, self.get_list().__str__())

	def to_display_value(self, value, db=None):
		return value

	# ----------------------------------------------------
	## Property
	list = ESiPCProperty(get_list, None, None)
	isentitylist = ESiPCProperty(is_entity_list, None, None)

# ------------------------------------------------------------
## Mikan 抽象リスト クラス
#
class AbstractMikanConstantList(AbstractMikanList):

	def get_list(self):
		return self.FList

	# ----------------------------------------------------
	## コンストラクタ
	#  @param self クラス自身
	def __init__(self):
		super(AbstractMikanConstantList, self).__init__()

		self.FList = {}

	def add_constant(self, constant):
		self.logger.debug(constant.key)
		self.FList[unicode(constant.key)] = constant

	def to_display_value(self, value, db=None):
		if value == None:
			return value
		try:
			return self.list[unicode(value)].to_display_value()
		except:
			# ログ
			self.logger.debug(self.list)
			self.logger.debug(unicode(value))
			self.logger.debug(value)
			self.logger.error(traceback.format_exc())
		return value

# ------------------------------------------------------------
## Mikan 抽象リスト クラス
#
class AbstractMikanEntityList(AbstractMikanList):

	def is_loaded(self):
		return self.FList != None

	def get_list(self):
		return self.FList

	def get_entity_class(self):
		return None

	# ----------------------------------------------------
	## コンストラクタ
	#  @param self クラス自身
	def __init__(self):
		super(AbstractMikanEntityList, self).__init__()

		self.FList = None

	def get_item_name(self):
		return self.entityclass().itemname

	def build_list(self, db):
		if not self.isloaded:
			for i in db.gets(self.entityclass):
				self.add_entity(i)

	def add_entity(self, entity):
		if self.FList == None:
			self.FList = {}
		self.logger.debug(entity.getIDValue())
		self.FList[unicode(entity.getIDValue())] = entity

	def to_display_value(self, value, db=None):
		if (value == None) or (value == ""):
			return value
		if self.isloaded:
			if not self.list.has_key(value):
				return value
		elif db != None:
			try:
				e = db.get(value).to_display_value()
			except:
				return None

		try:
			a = self.list[value]
			if a:
				return a.to_display_value()
		except:
			# ログ
			self.logger.debug(self.list)
			self.logger.debug(value)
			self.logger.error(traceback.format_exc())
		return value

	# ----------------------------------------------------
	## Property
	isloaded = ESiPCProperty(is_loaded, None, None)
	entityclass = ESiPCProperty(get_entity_class, None, None)

# ------------------------------------------------------------
## Mikan 抽象リスト クラス
#
class MikanEntityList(AbstractMikanEntityList):

	def get_entity_class(self):
		return self.FEntityClass

	# ----------------------------------------------------
	## コンストラクタ
	#  @param self クラス自身
	def __init__(self, entityclass):
		super(MikanEntityList, self).__init__()

		self.FEntityClass = entityclass

# ------------------------------------------------------------
## Mikan 抽象エンティティ クラス
#
class AbstractMikanEntity(AbstractMikanItem):

	def onCreate(self):
		if self.is_id_entity():
			self.id = ObjectId().__str__()
		self.onCreateUpdate()

		if self.issequenceentity:
			self.setEffectiveSequenceValue(True)
			self.setLastSequenceValue(True)

	def onCreateUpdate(self):
		pass

	def onUpdate(self):
		self.onCreateUpdate()

	def get_key(self):
		return self.getIDValue()

	def get_sort_attributes(self):
		try:
			return [(self.getNameAttribute(), False)]
		except:
			return None

	def to_display_value(self):
		try:
			return self.getNameValue()
		except:
			pass
		return self.itemcaption

	def add_attribute(self, attribute):
		self.FAttributes[attribute.definename] = attribute

	def get_attribute(self, name):
		try:
			return self.attributes[name]
		except:
			self.logger.error(name)
			self.logger.error(self.FAttributes)
			raise

	def get_item_name(self):
		return super(AbstractMikanEntity, self).get_item_name().replace("Entity", "")

	# ----------------------------------------------------
	## 属性 フィールドゲッター
	def get_attributes(self):
		return self.FAttributes

	def sorted_attributes(self):
		return sorted(self.attributes.values(), key=attrgetter("FSortKey"))

	# ----------------------------------------------------
	## 値 フィールドゲッター
	def get_values(self):
		return self.__dict__

	def export_values(self, dynamic=True):
		q = {}
		for k,v in self.values.items():
			if self.attributes.has_key(k):
				if self.attributes[k].is_dynamic() == False:
					a = v
					if self.attributes[k].classtype == "bool":
						if v == 1:
							a = True
						elif v == 0:
							a = False
					q[k] = a
		return q

	# ----------------------------------------------------
	## コンストラクタ
	#  @param self クラス自身
	#  @param values 値
	def __init__(self, values=None):
		super(AbstractMikanEntity, self).__init__()

		if values:
			self.__dict__.update(values)

		self.init_attibutes()

	def init_attibutes(self):
		self.FAttributes = {}

	def __getitem__(self, index):
		if self.values.has_key(index):
			return self.values[index]
		return None

	def __setitem__(self, index, value):
		self.values[index] = value

	def __str__(self):
		return self.itemname + ": " + self.values.__str__()

	def get_sequence_value_default(self):
		return 0

	def get_sequence_format(self):
		return '%02d'

	def is_sequence_entity(self):
		try:
			self.getRootIDAttribute()
			return True
		except:
			return False

	def is_id_entity(self):
		try:
			self.getIDAttribute()
			return True
		except:
			return False

	def is_date_entity(self):
		try:
			self.getCreateDateAttribute()
			return True
		except:
			return False

	# ----------------------------------------------------
	## Property
	key = ESiPCProperty(get_key, None, None)
	values = ESiPCProperty(get_values, None, None)
	attributes = ESiPCProperty(get_attributes, None, None)
	issequenceentity = ESiPCProperty(is_sequence_entity, None, None)
	sequenceformat = ESiPCProperty(get_sequence_format, None, None)
	sequencevaluedefault = ESiPCProperty(get_sequence_value_default, None, None)
	sortattributes = ESiPCProperty(get_sort_attributes, None, None)

# ------------------------------------------------------------
## Mikan 抽象フォーム クラス
#
class AbstractMikanForm(AbstractMikanItem):

	# ----------------------------------------------------
	## コンストラクタ
	#  @param self クラス自身
	def __init__(self, entity=None):
		super(AbstractMikanForm, self).__init__()

		self.FEntity = entity
		self.FFields = {}

	def defaults(self, entity):
		pass

	def get_icon_value(self):
		return self.entity.iconname

	def get_base_caption(self):
		if (self.entity != None):
			return self.entity.itemcaption
		return ""

	def addField(self, field):
		self.add_field(field)

	def add_field(self, field):
		self.fields[field.definename] = field

	def get_item_name(self):
		return super(AbstractMikanForm, self).get_item_name().replace("Form", "")

	def getValue(self, name):
		return self.get_value(name)

	def get_value(self, name):
		return self.entity[name]

	def get_value_string(self, name):
		return self.entity[name]

	def is_readonly(self):
		return False

	def is_result_type(self):
		return True

	def get_fields(self):
		return self.FFields

	def sorted_fields(self):
		return sorted(self.fields.values(), key=attrgetter('FY'))

	def get_field(self, name):
		return self.fields[name]

	def get_attribute(self, name):
		if (self.entity != None):
			return self.entity.get_attribute(name)
		return None

	def set_entity(self, value):
		self.FEntity = value

	def get_entity(self):
		return self.FEntity

	def get_item_caption(self):
		key = self.get_item_resource_key("caption")
		if self.islogdebug:
			self.logger.debug(key)

		ic = self.itemresource.get_string(key, self.itemname, locale.getlocale())
		if self.islogdebug:
			self.logger.debug(ic)
		return u"%s %s" % (self.basecaption, ic)

	# ----------------------------------------------------
	## Property
	entity = ESiPCProperty(get_entity, set_entity, None)
	fields = ESiPCProperty(get_fields, set_entity, None)
	basecaption = ESiPCProperty(get_base_caption, None, None)
	iconvalue = ESiPCProperty(get_icon_value, None, None)


# ------------------------------------------------------------
## Mikan 抽象フォーム クラス
#
class AbstractMikanField(AbstractMikanItem):

	# ----------------------------------------------------
	## コンストラクタ
	#  @param self クラス自身
	def __init__(self):
		super(AbstractMikanField, self).__init__()

	def get_base_caption(self):
		return self.attribute.itemcaption

	def get_item_name(self):
		return super(AbstractMikanField, self).itemname.replace("Field", "")

	def get_json_type(self):
		if self.ispassword:
			return "password"


		return "text"

	def get_length(self):
		return self.attribute.length

	def is_date(self):
		try:
			return self.attribute.classtype == "date"
		except:
			return False

	def is_time(self):
		try:
			return self.attribute.classtype == "time"
		except:
			return False

	def is_datetime(self):
		try:
			return self.attribute.classtype == "timestamp"
		except:
			return False

	def is_readonly(self):
		return False

	def is_result_type(self):
		return True

	def is_required(self):
		return False

	def is_enabled(self):
		return True

	def is_password(self):
		try:
			return self.attribute.classtype == "password"
		except:
			return False

	def is_visibled(self):
		return True

	def is_multi_line(self):
		return False

	def get_default(self):
		return None

	def get_x(self):
		return None

	def get_y(self):
		return None

	def get_form(self):
		return None

	def get_entity(self):
		return self.form.entity

	def get_width(self):
		return 64

	def get_height(self):
		if self.ismultiline:
			return 6
		return 1

	def get_attribute(self):
		return self.form.get_attribute(self.itemname)

	# ----------------------------------------------------
	## Property
	basecaption = ESiPCProperty(get_base_caption, None, None)
	isrequired = ESiPCProperty(is_required, None, None)
	isresulttype = ESiPCProperty(is_result_type, None, None)
	ismultiline = ESiPCProperty(is_multi_line, None, None)
	ispassword = ESiPCProperty(is_password, None, None)
	isreadonly = ESiPCProperty(is_readonly, None, None)
	isenabled = ESiPCProperty(is_enabled, None, None)
	isvisibled = ESiPCProperty(is_visibled, None, None)
	attribute = ESiPCProperty(get_attribute, None, None)
	jsontype = ESiPCProperty(get_json_type, None, None)
	form = ESiPCProperty(get_form, None, None)
	default = ESiPCProperty(get_default, None, None)
	entity = ESiPCProperty(get_entity, None, None)
	x = ESiPCProperty(get_x, None, None)
	y = ESiPCProperty(get_y, None, None)
	istime = ESiPCProperty(is_time, None, None)
	isdatetime = ESiPCProperty(is_datetime, None, None)
	isdate = ESiPCProperty(is_date, None, None)
	width = ESiPCProperty(get_width, None, None)
	height = ESiPCProperty(get_height, None, None)

# ------------------------------------------------------------
## Mikan 抽象フォーム クラス
#
class MikanField(AbstractMikanField):

	# ----------------------------------------------------
	## コンストラクタ
	#  @param self クラス自身
	def __init__(self, form, name, caption, readonly, resulttype, required, enabled, visibled, multiline, default, x, y, width, height):
		super(MikanField, self).__init__()

		self.FForm = form
		self.FItemName = name
		self.FCaption = caption
		self.FReadonly = readonly
		self.FResultType = resulttype
		self.FRequired = required
		self.FEnabled = enabled
		self.FVisibled = visibled
		self.FMultiLine = multiline
		self.FDefault = default
		self.FX = x
		self.FY = y
		self.FWidth = width
		self.FHeight = height

	def get_base_caption(self):
		if (self.form == None):
			return None
		if (self.FItemName == None):
			return None
		attribute = self.form.get_attribute(self.FItemName)
		if (attribute == None):
			return None
		return attribute.itemcaption

	def get_item_caption(self):
		value = self.FCaption
		if (value == None):
			return self.basecaption
		return value

	def get_item_name(self):
		return self.FItemName

	def get_form(self):
		return self.FForm

	def is_readonly(self):
		value = self.FReadonly
		if (value == None):
			return super(MikanField, self).is_readonly()
		return value

	def is_result_type(self):
		value = self.FResultType
		if (value == None):
			return super(MikanField, self).is_result_type()
		return value

	def is_required(self):
		value = self.FRequired
		if (value == None):
			return super(MikanField, self).is_required()
		return value

	def is_enabled(self):
		value = self.FEnabled
		if (value == None):
			return super(MikanField, self).is_enabled()
		return value

	def is_visibled(self):
		value = self.FVisibled
		if (value == None):
			return super(MikanField, self).is_visibled()
		return value

	def is_multi_line(self):
		value = self.FMultiLine
		if (value == None):
			return super(MikanField, self).is_multi_line()
		return value

	def get_default(self):
		value = self.FDefault
		if (value == None):
			return super(MikanField, self).get_default()
		return value

	def get_x(self):
		value = self.FX
		if (value == -1) or (value == None):
			return super(MikanField, self).get_x()
		return value

	def get_y(self):
		value = self.FY
		if (value == -1) or (value == None):
			return super(MikanField, self).get_y()
		return value

	def get_width(self):
		value = self.FWidth
		if (value == -1) or (value == None):
			return super(MikanField, self).get_width()
		return value

	def get_height(self):
		value = self.FHeight
		if (value == -1) or (value == None):
			return super(MikanField, self).get_height()
		return value

# ------------------------------------------------------------
## Main Section
# ------------------------------------------------------------
if __name__ == '__main__':
	pass

# ------------------------------------------------------------
